package com.smallrig.extension.ext;


import com.smallrig.extension.ExtensionSpi;
import com.smallrig.extension.chain.Command;
import com.smallrig.extension.chain.Context;
import com.smallrig.extension.dto.BizSceneWrapper;
import com.smallrig.extension.dto.BizScene;
import com.smallrig.extension.dto.BizScenes;
import com.smallrig.extension.utils.SpiUtils;

import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

public abstract class AbstractComponentExecutor {

    public <R, T> R execute(Class<T> targetClz, Context context) {
        return execute(targetClz,BizScenes.empty(),context);
    }

    public <R, T> R execute(Class<T> targetClz, BizScenes bizScenes, Context context) {
        List<T> components = load(targetClz, bizScenes);
        for (T component : components) {
            Command command = (Command) component;
            command.preHandler(context);
            boolean ret = command.execute(context);
            command.postHandler(context);
            if (ret) {
                break;
            }
        }
        return null;
    }

    public <T> List<T> load(Class<T> targetClz,BizScenes bizScenes) {
        return locateComponent(targetClz, bizScenes);
    }

    public <T> List<T> load(Class<T> targetClz) {
        return load(targetClz,BizScenes.empty());
    }


    public <T> T load(Class<T> targetClz, BizScene bizScene) {
        List<T> components = load(targetClz, BizScenes.valueOf(bizScene));
        return components.get(0);
    }

    public <R, T> R execute(Class<T> targetClz, BizScene bizScene, Function<T, R> exeFunction) {
        return exeFunction.apply(load(targetClz,bizScene));
    }


    public <T> void executeVoid(Class<T> targetClz, BizScene bizScene, Consumer<T> exeFunction) {
        exeFunction.accept(load(targetClz,bizScene));
    }

    public <T> void executeVoid(BizSceneWrapper bizSceneWrapper, Consumer<T> exeFunction){
        executeVoid(bizSceneWrapper.getExtensionClass(), bizSceneWrapper.getBizScenario(), exeFunction);
    }

    /**
     * 策略查找逻辑
     * @param targetClz
     * @param bizScene
     * @param <C>
     * @return
     */
    protected abstract <C> C locateComponent(Class<C> targetClz, BizScene bizScene);

    /**
     * 责任链查找逻辑
     * @param targetClz
     * @param bizScenes
     * @param <C>
     * @return
     */
    protected abstract <C> List<C> locateComponent(Class<C> targetClz, BizScenes bizScenes);

}
